/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package unc.pds.model;

import java.rmi.RemoteException;
import java.util.Date;
import java.util.Collection;
import java.util.List;
import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import unc.pds.auth.SecurityST;
import unc.pds.data.Consts;
import unc.pds.data.RootDataBeanRemote;
import unc.pds.data.RootDataBeanRemoteHome;
import unc.pds.exc.PDSSecurityException;
import unc.pds.filemodel.AlbumRemote;
import unc.pds.filemodel.AlbumRemoteHome;
import unc.pds.filemodel.FolderRemote;
import unc.pds.filemodel.FolderRemoteHome;
import unc.pds.news.NewsMessage;
import unc.pds.util.Arch;
import unc.pds.util.ArchImpl;

/**
 *
 * @author ain
 */
public class Group implements SessionBean, IGroup {

    private static String default_object_type = Consts.OBJECT_TYPE__GROUP;
    private SessionContext context;
    private Long sessionKey;
    unc.pds.data.RootDataBeanRemote dataBean;

    // <editor-fold defaultstate="collapsed" desc="EJB infrastructure methods. Click the + sign on the left to edit the code.">;
    // TODO Add code to acquire and use other enterprise resources (DataSource, JMS, enterprise bean, Web services)
    // TODO Add business methods or web service operations
    /**
     * @see javax.ejb.SessionBean#setSessionContext(javax.ejb.SessionContext)
     */
    public void setSessionContext(SessionContext aContext) {
        context = aContext;
    }

    /**
     * @see javax.ejb.SessionBean#ejbActivate()
     */
    public void ejbActivate() {
    }

    /**
     * @see javax.ejb.SessionBean#ejbPassivate()
     */
    public void ejbPassivate() {
    }

    /**
     * @see javax.ejb.SessionBean#ejbRemove()
     */
    public void ejbRemove() {
    }

    // </editor-fold>;
    public void ejbCreate(unc.pds.data.RootDataBeanRemote rdb, Long nsessionKey) throws RemoteException {
        dataBean = rdb;
        sessionKey = nsessionKey;
        dataBean.setSessionKey(sessionKey);
    }

    public void ejbCreate(Long id, Long nsessionKey) throws NamingException, RemoteException {
        try {
            RootDataBeanRemoteHome rdbrh = (RootDataBeanRemoteHome) (new InitialContext()).lookup("ejb/RootDataBean");
            dataBean = rdbrh.findByPrimaryKey(id);
        } catch (Exception e) {
            throw new EJBException(e.getLocalizedMessage());
        }
        sessionKey = nsessionKey;
        dataBean.setSessionKey(sessionKey);
    }

    public Date getDate() throws RemoteException{
        return dataBean.getCrDate();
    }

    public void ejbCreate(Arch doc, Long nsessionKey) throws CreateException, RemoteException {
        sessionKey = nsessionKey;
        try {
            if (doc.getChild(Consts.ARCH_F_TYPE) == null) {
                doc.addChild(new ArchImpl(Consts.ARCH_F_TYPE, Consts.OBJECT_TYPE__GROUP));
            }
            RootDataBeanRemoteHome rdbrh = (RootDataBeanRemoteHome) (new InitialContext()).lookup("ejb/RootDataBean");
            dataBean = rdbrh.create(doc, sessionKey);
            dataBean.setSessionKey(sessionKey);
        } catch (Exception nex) {
            throw new CreateException(default_object_type + " CREATEbyDOC: " + nex.getLocalizedMessage());
        }
    }

    public String getName() throws RemoteException {
        return dataBean.getParameter(Consts.ATTR__GROUP_NAME);
    }

    public void setName(String nname) throws RemoteException {
        dataBean.setParameter(Consts.ATTR__GROUP_NAME, nname);
    }

    public DiaryRemote[] getDiares() throws RemoteException {
        try {
            DiaryRemoteHome drh =
                    (DiaryRemoteHome) (new InitialContext()).lookup("ejb/Diary");
            RootDataBeanRemoteHome rdbrh =
                    (RootDataBeanRemoteHome) (new InitialContext()).lookup("ejb/RootDataBean");
            Collection bean = rdbrh.findByParentKey(this.getKey(), Consts.OBJECT_TYPE__DIARY);

            DiaryRemote[] ans = new DiaryRemote[bean.size()];
            for (int i = 0; i < bean.size(); i++) {
                ((RootDataBeanRemote) (bean.toArray()[i])).setSessionKey(sessionKey);
                ans[i] = drh.create((RootDataBeanRemote) (bean.toArray()[i]), sessionKey);
            }
            return ans;
        } catch (Exception e) {
            throw new RemoteException("Group.GETDIARES: " + e.getLocalizedMessage());
        }
    }

    public void addDiary(Arch doc) throws RemoteException {
        try {
            DiaryRemoteHome drh = (DiaryRemoteHome) (new InitialContext()).lookup("ejb/Diary");
            doc.addChild(new ArchImpl(Consts.ARCH_F_PARENT, dataBean.getPrimaryKey().toString()));
            doc.addChild(new ArchImpl(Consts.ATTR__DIARY_CONTEXT, dataBean.getPrimaryKey().toString()));
            DiaryRemote DR = drh.create(doc, sessionKey);
            if (Consts.DEBUG_MODE) System.out.println("Group.addDiary: created ");
            //dataBean.addParameter(Consts.ATTR__USER_DIARY, DR.getKey().toString());
            generateNews("create", DR.getKey());
        } catch (Exception e) {
            if (Consts.DEBUG_MODE) System.out.println("ERROR:Group.addDiary: " + e.getLocalizedMessage());
            throw new RemoteException("Group.addDiary: " + e.getLocalizedMessage());
        }
    }


    public AlbumRemote[] getAlbums() throws RemoteException {
        try {
            AlbumRemoteHome drh =
                    (AlbumRemoteHome) (new InitialContext()).lookup("ejb/Album");
            RootDataBeanRemoteHome rdbrh =
                    (RootDataBeanRemoteHome) (new InitialContext()).lookup("ejb/RootDataBean");
            Collection bean = rdbrh.findByParentKey(this.getKey(), Consts.OBJECT_TYPE__ALBUM);

            AlbumRemote[] ans = new AlbumRemote[bean.size()];
            for (int i = 0; i < bean.size(); i++) {
                ((RootDataBeanRemote) (bean.toArray()[i])).setSessionKey(sessionKey);
                ans[i] = drh.create((RootDataBeanRemote) (bean.toArray()[i]), sessionKey);
            }
            return ans;
        } catch (Exception e) {
            throw new RemoteException("Group.GETAlbumS: " + e.getLocalizedMessage());
        }
    }

    public void addAlbum(Arch doc) throws RemoteException {
        try {
            AlbumRemoteHome drh = (AlbumRemoteHome) (new InitialContext()).lookup("ejb/Album");
            doc.addChild(new ArchImpl(Consts.ARCH_F_PARENT, dataBean.getPrimaryKey().toString()));
            doc.addChild(new ArchImpl(Consts.ATTR__ALBUM_CONTEXT, dataBean.getPrimaryKey().toString()));
            AlbumRemote DR = drh.create(doc, sessionKey);
            if (Consts.DEBUG_MODE) System.out.println("Group.addAlbum: created ");
        } catch (Exception e) {
            if (Consts.DEBUG_MODE) System.out.println("ERROR:Group.addAlbum: " + e.getLocalizedMessage());
            throw new RemoteException("Group.addAlbum: " + e.getLocalizedMessage());
        }
    }

    public FolderRemote[] getFolders() throws RemoteException {
        try {
            FolderRemoteHome drh =
                    (FolderRemoteHome) (new InitialContext()).lookup("ejb/Folder");
            RootDataBeanRemoteHome rdbrh =
                    (RootDataBeanRemoteHome) (new InitialContext()).lookup("ejb/RootDataBean");
            Collection bean = rdbrh.findByParentKey(this.getKey(), Consts.OBJECT_TYPE__FOLDER);

            FolderRemote[] ans = new FolderRemote[bean.size()];
            for (int i = 0; i < bean.size(); i++) {
                ((RootDataBeanRemote) (bean.toArray()[i])).setSessionKey(sessionKey);
                ans[i] = drh.create((RootDataBeanRemote) (bean.toArray()[i]), sessionKey);
            }
            return ans;
        } catch (Exception e) {
            throw new RemoteException("Group.getFolders: " + e.getLocalizedMessage());
        }
    }

    public void addFolder(Arch doc) throws RemoteException {
        try {
            FolderRemoteHome drh = (FolderRemoteHome) (new InitialContext()).lookup("ejb/Folder");
            doc.addChild(new ArchImpl(Consts.ARCH_F_PARENT, dataBean.getPrimaryKey().toString()));
            doc.addChild(new ArchImpl(Consts.ATTR__FOLDER_CONTEXT, dataBean.getPrimaryKey().toString()));
            FolderRemote DR = drh.create(doc, sessionKey);
            if (Consts.DEBUG_MODE) System.out.println("User.addFolder: created ");
        } catch (Exception e) {
            if (Consts.DEBUG_MODE) System.out.println("ERROR:Group.addFolder: " + e.getLocalizedMessage());
            throw new RemoteException("Group:addFolder: " + e.getLocalizedMessage());
        }
    }

    private void generateNews(String event, Long eventID) throws RemoteException{
        try {
            QueueConnectionFactory connfac = (QueueConnectionFactory) (new InitialContext()).lookup("jms/newsQueueConnection");
            QueueConnection conn = connfac.createQueueConnection();
            QueueSession sess = conn.createQueueSession(true, QueueSession.AUTO_ACKNOWLEDGE);

            Queue queue = (Queue) (new InitialContext()).lookup("jms/newsQueue");
            QueueSender sender = sess.createSender(queue);
            if (Consts.DEBUG_MODE) System.out.println("sender created");
            NewsMessage m = new NewsMessage();
            m.setLongProperty(NewsMessage.CONTEXT_ID_KEY, getKey().longValue());
            m.setStringProperty(NewsMessage.EVENT_NAME_KEY, event);
            m.setLongProperty(NewsMessage.ENTITY_ID_KEY, eventID.longValue());
            if (Consts.DEBUG_MODE) System.out.println("Filled message");
            sender.send(m);
            if (Consts.DEBUG_MODE) System.out.println("message sended");
            sender.close();
            sess.close();
            conn.close();
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new RemoteException("getNews: "+ex.toString());
        }
    }

    public void wasInvitedByUser(Long key) throws RemoteException {
        dataBean.addParameter(Consts.ATTR__GROUP_NEWMEMBER, key.toString());
    }

    public void sendInviteToUser(Long key) throws RemoteException {
        UserRemote user = (UserRemote) ModelFactory.getByKey(key, sessionKey);
        user.wasInvitedByGroup(getKey());
        dataBean.addParameter(Consts.ATTR__GROUP_WANTEDMEMBER, key.toString());
    }

    public void acceptUserInvite(Long key) throws RemoteException {
        if (isNewMember(key)){
            UserRemote user = (UserRemote) ModelFactory.getByKey(key, sessionKey);
            user.wasAcceptedByGroup(getKey());
            dataBean.addParameter(Consts.ATTR__GROUP_MEMBER, key.toString());
            dataBean.dropParameter(Consts.ATTR__GROUP_NEWMEMBER, key.toString());
        }
    }

    public void delcineUserInvite(Long key) throws RemoteException {
        if (isNewMember(key)){
            UserRemote user = (UserRemote) ModelFactory.getByKey(key, sessionKey);
            user.wasDeclinedByGroup(getKey());
            dataBean.dropParameter(Consts.ATTR__GROUP_NEWMEMBER, key.toString());
        }
    }

    public void wasAcceptedByUser(Long key) throws RemoteException {
        if (isWantedMember(key)) {
            dataBean.dropParameter(Consts.ATTR__GROUP_WANTEDMEMBER, key.toString());
            dataBean.addParameter(Consts.ATTR__GROUP_MEMBER, key.toString());
        }
    }

    public void wasDeclinedByUser(Long key) throws RemoteException {
        if (isWantedMember(key)) {
            dataBean.dropParameter(Consts.ATTR__GROUP_WANTEDMEMBER, key.toString());
        }
    }

    public void removeMember(Long key) throws RemoteException {
        if (isMember(key)) {
            UserRemote user = (UserRemote) ModelFactory.getByKey(key, sessionKey);
            user.wasRemovedFromGroupBy(getKey());
            dataBean.dropParameter(Consts.ATTR__GROUP_MEMBER, key.toString());
        }
    }

    public void wasRemovedFromGroupsBy(Long key) throws RemoteException {
        if (isMember(key)) {
            dataBean.dropParameter(Consts.ATTR__GROUP_MEMBER, key.toString());
        }
    }

    public void banMember(Long key) throws RemoteException {
        if (isMember(key)) {
            try {
                dataBean.addParameter(Consts.ATTR__GROUP_BANNEDMEMBER, key.toString());
                dataBean.dropParameter(Consts.ATTR__GROUP_MEMBER, key.toString());
                SecurityST.getSecurityApplyer(sessionKey).onBanMember(getKey(), key);
            } catch (PDSSecurityException ex) {
                ex.printStackTrace();
                throw new RemoteException(ex.toString());
            }
        }
    }

    public void unbanMember(Long key) throws RemoteException {
        if (isBannedMember(key)) {
            try {
                dataBean.addParameter(Consts.ATTR__GROUP_MEMBER, key.toString());
                dataBean.dropParameter(Consts.ATTR__GROUP_BANNEDMEMBER, key.toString());
                SecurityST.getSecurityApplyer(sessionKey).onUnBanMember(getKey(), key);
            } catch (PDSSecurityException ex) {
                ex.printStackTrace();
                throw new RemoteException(ex.toString());
            }
        }
    }

    public void upToModer(Long key) throws RemoteException {
        if (isMember(key)) {
            try {
                dataBean.addParameter(Consts.ATTR__GROUP_MODERATOR, key.toString());
                dataBean.dropParameter(Consts.ATTR__GROUP_MEMBER, key.toString());
                SecurityST.getSecurityApplyer(sessionKey).onNewModer(getKey(), key);
            } catch (PDSSecurityException ex) {
                ex.printStackTrace();
                throw new RemoteException(ex.toString());
            }
        }
    }

    public void downFromModer(Long key) throws RemoteException {
        if (isModer(key)) {
            try {
                dataBean.addParameter(Consts.ATTR__GROUP_MEMBER, key.toString());
                dataBean.dropParameter(Consts.ATTR__GROUP_MODERATOR, key.toString());
                SecurityST.getSecurityApplyer(sessionKey).onDelModer(getKey(), key);
            } catch (PDSSecurityException ex) {
                ex.printStackTrace();
                throw new RemoteException(ex.toString());
            }
        }
    }

    private UserRemote[] getUsersByMemberStatus(String status) throws RemoteException {
        try {
            String[] list = dataBean.getParameters(status);
            UserRemote[] ans = new UserRemote[list.length];
            for (int i = 0; i < ans.length; i++) {
                ans[i] = (UserRemote) ModelFactory.getByKey(new Long(Long.parseLong(list[i])), sessionKey);
            }
            return ans;
        } catch (Exception e) {
            throw new RemoteException("Group.getUserByMemberStatus: " + e.getLocalizedMessage());
        }
    }

    public UserRemote[] getMembers() throws RemoteException {
        UserRemote[] members = getUsersByMemberStatus(Consts.ATTR__GROUP_MEMBER);
        UserRemote[] moders = getUsersByMemberStatus(Consts.ATTR__GROUP_MODERATOR);
        UserRemote[] ans = new UserRemote[members.length+moders.length+1];
        System.arraycopy(members, 0, ans, 0, members.length);
        System.arraycopy(moders, 0, ans, members.length, moders.length);
        ans[ans.length-1]=getOwner();
        return ans;
    }

    public UserRemote[] getNewMembers() throws RemoteException {
        return getUsersByMemberStatus(Consts.ATTR__GROUP_NEWMEMBER);
    }

    public UserRemote[] getBanMembers() throws RemoteException {
        return getUsersByMemberStatus(Consts.ATTR__GROUP_BANNEDMEMBER);
    }

    public UserRemote[] getModers() throws RemoteException {
        return getUsersByMemberStatus(Consts.ATTR__GROUP_MODERATOR);
    }

    public boolean isMember(Long key) throws RemoteException {
        return (dataBean.hasField(Consts.ATTR__GROUP_MEMBER, key.toString())||
                isModer(key)||key.equals(getOwner().getKey()));
    }

    public boolean isWantedMember(Long key) throws RemoteException {
        return dataBean.hasField(Consts.ATTR__GROUP_WANTEDMEMBER, key.toString());
    }

    public boolean isNewMember(Long key) throws RemoteException {
        return dataBean.hasField(Consts.ATTR__GROUP_NEWMEMBER, key.toString());
    }

    public boolean isBannedMember(Long key) throws RemoteException {
        return dataBean.hasField(Consts.ATTR__GROUP_BANNEDMEMBER, key.toString());
    }

    public boolean isModer(Long key) throws RemoteException {
        return dataBean.hasField(Consts.ATTR__GROUP_MODERATOR, key.toString());
    }

    public Long getKey() throws RemoteException {
        return (Long) dataBean.getPrimaryKey();
    }

    public String getType() throws RemoteException {
        return default_object_type;
    }

    public Model getParent() throws RemoteException {
        return ModelFactory.getByKey(dataBean.getParentID(), sessionKey);
    }

    public UserRemote getOwner() throws RemoteException{
        return (UserRemote) getParent();
    }

    public void dropMe() throws RemoteException {
        try {
            dataBean.dropMe();
        } catch (Exception e) {
            throw new RemoteException(e.getLocalizedMessage());
        }
    }

    public List getRolesForUser(Long key) throws RemoteException {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
